package com.wjk.kylin.mall.product.utils;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * 查询es工具类
 */
@Slf4j
@Component
public class EsClientUtil {
    @Autowired
    private RestHighLevelClient client;


    /**
     * 游标首次查询
     *
     * @param index
     * @param time
     * @param builder
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> EsIterator<T> selectEsIterator(String index, long time, SearchSourceBuilder builder, Class<T> clazz) {
        //索引
        if (StringUtils.isBlank(index)) {
            throw new NullPointerException("index is null");
        }
        //查询条件
        if (builder == null) {
            throw new NullPointerException("builder is null");
        }
        //游标id存活时间
        if (time <= 0) {
            time = 1L;
        }

        try {
            //定义请求对象
            SearchRequest request = new SearchRequest(index);
            //设置查询条件
            request.source(builder);
            //设置游标id存活时间
            Scroll scroll = new Scroll(TimeValue.timeValueMinutes(time));
            request.scroll(scroll);

            // 首次查询需要指定索引名称和查询条件
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            if (!RestStatus.OK.equals(response.status())) {
                log.error("selectEsIterator query es status is not ok ,status:{}", response.status());
                throw new RuntimeException("query es status is" + response.status());
            }
            // 下一次搜索要用到该游标id
            String scrollId = response.getScrollId();
            SearchHits hits = response.getHits();
            long totalSize = hits.getTotalHits().value;

            List<T> rows = new ArrayList<>();
            for (SearchHit hit : hits) {
                JSONObject jsonObject = JSONObject.parseObject(hit.getSourceAsString());
                rows.add(JSONObject.toJavaObject(jsonObject, clazz));
            }

            log.info("selectEsIterator-scrollId:{},time:{},totalSize:{},rows.size:{}", scrollId, time, totalSize, rows.size());

            return new EsIterator<>(scroll, scrollId, this, totalSize, rows, clazz);
        } catch (Exception e) {
            log.error("selectEsIterator query es error:", e);
        }

        return null;
    }


    /**
     * 游标非首次查询
     *
     * @param scroll
     * @param scrollId
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> List<T> selectScroll(Scroll scroll, String scrollId, Class<T> clazz) {
        log.info("selectScroll-scroll:{},scrollId:{}", scroll, scrollId);

        try {
            //不需要在使用其他条件，也不需要指定索引名称，只需要使用执行游标id存活时间和上次游标id即可，毕竟信息都在上次游标id里面呢
            SearchScrollRequest request = new SearchScrollRequest(scrollId);
            //再指定scroll的生存时间，若不指定它会归零
            request.scroll(scroll);
            SearchResponse response = client.scroll(request, RequestOptions.DEFAULT);

            if (!RestStatus.OK.equals(response.status())) {
                log.error("selectEsIterator query es status is not ok ,status:{}", response.status());
                throw new RuntimeException("query es status is" + response.status());
            }

            List<T> rows = new ArrayList<>();
            for (SearchHit hit : response.getHits()) {
                JSONObject jsonObject = JSONObject.parseObject(hit.getSourceAsString());
                rows.add(JSONObject.toJavaObject(jsonObject, clazz));
            }

            log.info("selectScroll-new scrollId:{},totalSize:{},rows.size:{}", response.getScrollId(), response.getHits().getTotalHits().value, rows.size());
            return rows;
        } catch (Exception e) {
            log.error("selectScroll query es error:", e);
        }

        return null;
    }

    /**
     * 清除游标,超时也会自动清除
     */

}
